package com.matrix.review.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.matrix.api.merchant.MerchantApi;
import com.matrix.api.order.OrderApi;
import com.matrix.api.order.vo.OrderForReviewVO;
import com.matrix.api.order.vo.OrderItemForReviewVO;
import com.matrix.api.product.ProductApi;
import com.matrix.api.product.vo.ProductVO;
import com.matrix.api.merchant.vo.ShopInfoVO;
import com.matrix.api.review.dto.ReviewDTO;
import com.matrix.api.review.dto.ReviewItemDTO;
import com.matrix.api.review.dto.ReviewReplyDTO;
import com.matrix.api.review.vo.ReviewItemVO;
import com.matrix.api.review.vo.ReviewVO;
import com.matrix.api.user.UserApi;
import com.matrix.api.user.vo.UserInfoVO;
import com.matrix.common.constant.RocketMQConstants;
import com.matrix.common.domain.PageResult;
import com.matrix.common.exception.BusinessException;
import com.matrix.review.converter.ReviewConverter;
import com.matrix.review.entity.Review;
import com.matrix.review.entity.ReviewImage;
import com.matrix.review.entity.ReviewItem;
import com.matrix.review.entity.ReviewReply;
import com.matrix.review.mapper.ReviewImageMapper;
import com.matrix.review.mapper.ReviewItemMapper;
import com.matrix.review.mapper.ReviewMapper;
import com.matrix.review.mapper.ReviewReplyMapper;
import com.matrix.review.service.ReviewService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 有点甜
 * @since 2025/7/27
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReviewServiceImpl implements ReviewService {

    private final ReviewMapper reviewMapper;
    private final ReviewItemMapper reviewItemMapper;
    private final ReviewImageMapper reviewImageMapper;
    private final ReviewReplyMapper reviewReplyMapper;
    private final RocketMQTemplate rocketMQTemplate;

    @DubboReference(check = false)
    private OrderApi orderApi;
    @DubboReference(check = false)
    private MerchantApi merchantApi;
    @DubboReference(check = false)
    private UserApi userApi;
    @DubboReference(check = false)
    private ProductApi productApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitReview(Long userId, ReviewDTO reviewDTO) {
        OrderForReviewVO orderInfo;
        try {
            orderInfo = orderApi.checkOrderReviewable(reviewDTO.getOrderId(), userId);
        } catch (RpcException e) {
            throw new BusinessException("订单服务暂不可用,无法提交评价");
        }

        Long shopId = orderInfo.getShopId();
        Map<Long, Long> productIdMap = orderInfo.getItems().stream()
                .collect(Collectors.toMap(OrderItemForReviewVO::getOrderItemId, OrderItemForReviewVO::getProductId));

        Review review = ReviewConverter.INSTANCE.toReview(reviewDTO);
        review.setUserId(userId);
        review.setShopId(shopId);
        boolean hasContent = reviewDTO.getReviewItems().stream()
                .anyMatch(item -> StringUtils.hasText(item.getComment()) || (item.getImageUrls() != null && !item.getImageUrls().isEmpty()));
        review.setHasContent(hasContent);
        review.setStatus(0);
        reviewMapper.insert(review);

        for (ReviewItemDTO itemDTO : reviewDTO.getReviewItems()) {
            Long productId = productIdMap.get(itemDTO.getOrderItemId());
            if (productId == null) {
                continue;
            }
            ReviewItem reviewItem = ReviewConverter.INSTANCE.toReviewItem(itemDTO);
            reviewItem.setReviewId(review.getId());
            reviewItem.setProductId(productId);
            reviewItemMapper.insert(reviewItem);

            if (itemDTO.getImageUrls() != null && !itemDTO.getImageUrls().isEmpty()) {
                for (String imageUrl : itemDTO.getImageUrls()) {
                    ReviewImage reviewImage = new ReviewImage();
                    reviewImage.setReviewItemId(reviewItem.getId());
                    reviewImage.setImageUrl(imageUrl);
                    reviewImageMapper.insert(reviewImage);
                }
            }
        }

        try {
            orderApi.markOrderAsReviewed(reviewDTO.getOrderId());
        } catch (RpcException e) {
            throw new BusinessException("更新订单状态失败,评价提交终止");
        }

        rocketMQTemplate.convertAndSend(RocketMQConstants.REVIEW_STATS_TOPIC, review.getId());
        log.info("已为评价 {} 发送异步统计任务消息", review.getId());
    }

    @Override
    @Transactional
    public void replyToReview(Long userId, Long reviewId, ReviewReplyDTO replyDTO) {
        Long shopId = getShopIdByUserId(userId);
        Review review = reviewMapper.selectById(reviewId);
        if (review == null || !review.getShopId().equals(shopId)) {
            throw new BusinessException("评价不存在或无权操作");
        }
        if (reviewReplyMapper.selectCount(new LambdaQueryWrapper<ReviewReply>().eq(ReviewReply::getReviewId, reviewId)) > 0) {
            throw new BusinessException("请勿重复回复");
        }
        ReviewReply reply = ReviewConverter.INSTANCE.toReviewReply(replyDTO);
        reply.setReviewId(reviewId);
        reply.setShopId(shopId);
        reply.setUserId(userId);
        reviewReplyMapper.insert(reply);
    }

    @Override
    public PageResult<ReviewVO> getReviews(Long id, String type, int pageNum, int pageSize, String filter) {
        Page<Review> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Review> queryWrapper = new LambdaQueryWrapper<>();
        if ("SHOP".equalsIgnoreCase(type)) {
            queryWrapper.eq(Review::getShopId, id);
        } else {
            queryWrapper.eq(Review::getUserId, id);
        }
        if ("GOOD".equalsIgnoreCase(filter)) {
            queryWrapper.ge(Review::getOverallRating, 4);
        } else if ("BAD".equalsIgnoreCase(filter)) {
            queryWrapper.le(Review::getOverallRating, 2);
        }
        queryWrapper.orderByDesc(Review::getCreateTime);
        reviewMapper.selectPage(page, queryWrapper);

        List<Review> reviews = page.getRecords();
        if (reviews.isEmpty()) {
            return new PageResult<>(Collections.emptyList(), 0, 0);
        }

        List<Long> reviewIds = reviews.stream().map(Review::getId).toList();
        List<Long> userIds = reviews.stream().map(Review::getUserId).distinct().toList();

        List<ReviewItem> allReviewItems = reviewItemMapper.selectList(new LambdaQueryWrapper<ReviewItem>().in(ReviewItem::getReviewId, reviewIds));
        List<Long> productIds = allReviewItems.stream().map(ReviewItem::getProductId).distinct().toList();
        List<Long> allReviewItemIds = allReviewItems.stream().map(ReviewItem::getId).toList();

        Map<Long, UserInfoVO> userMap = getUsersInfo(userIds);
        Map<Long, ProductVO> productMap = getProductsInfo(productIds);
        Map<Long, ReviewReply> replyByReviewId = getRepliesForReviews(reviewIds);
        Map<Long, List<ReviewImage>> imagesByReviewItemId = getImagesForReviewItems(allReviewItemIds);

        Map<Long, List<ReviewItem>> itemsByReviewId = allReviewItems.stream().collect(Collectors.groupingBy(ReviewItem::getReviewId));

        List<ReviewVO> voList = reviews.stream().map(review -> {
            ReviewVO reviewVO = ReviewConverter.INSTANCE.toReviewVO(review);

            UserInfoVO userInfo = userMap.get(review.getUserId());
            if (review.getIsAnonymous() || userInfo == null) {
                reviewVO.setUserNickname("匿名用户");
                reviewVO.setUserAvatar("default_avatar_url");
            } else {
                reviewVO.setUserNickname(userInfo.getNickname());
                reviewVO.setUserAvatar(userInfo.getAvatar());
            }

            ReviewReply reply = replyByReviewId.get(review.getId());
            if (reply != null) {
                reviewVO.setReply(ReviewConverter.INSTANCE.toReviewReplyVO(reply));
            }

            List<ReviewItem> items = itemsByReviewId.getOrDefault(review.getId(), Collections.emptyList());
            List<ReviewItemVO> itemVOs = items.stream().map(item -> {
                ReviewItemVO itemVO = ReviewConverter.INSTANCE.toReviewItemVO(item);
                ProductVO productInfo = productMap.get(item.getProductId());
                if (productInfo != null) {
                    itemVO.setProductName(productInfo.getName());
                }
                List<ReviewImage> images = imagesByReviewItemId.getOrDefault(item.getId(), Collections.emptyList());
                itemVO.setImageUrls(images.stream().map(ReviewImage::getImageUrl).toList());
                return itemVO;
            }).toList();
            reviewVO.setReviewItems(itemVOs);

            return reviewVO;
        }).collect(Collectors.toList());

        return new PageResult<>(voList, page.getTotal(), page.getPages());
    }

    @Override
    public PageResult<ReviewVO> getReviewsForMerchant(Long merchantUserId, int pageNum, int pageSize, String filter) {
        Long shopId = getShopIdByUserId(merchantUserId);
        return getReviews(shopId, "SHOP", pageNum, pageSize, filter);
    }

    private Long getShopIdByUserId(Long userId) {
        try {
            ShopInfoVO shopInfo = merchantApi.getShopInfoByUserId(userId);
            if (shopInfo == null) {
                throw new BusinessException("您还没有创建店铺,请先完成入驻");
            }
            return shopInfo.getShopId();
        } catch (RpcException e) {
            throw new BusinessException("商家服务暂不可用");
        }
    }

    private Map<Long, UserInfoVO> getUsersInfo(List<Long> userIds) {
        if (userIds.isEmpty()) {
            return Collections.emptyMap();
        }
        try {
            return userApi.getUsersByIds(userIds).stream().collect(Collectors.toMap(UserInfoVO::getUid, Function.identity()));
        } catch (RpcException e) {
            log.warn("批量获取用户信息失败: {}", e.getMessage());
            return Collections.emptyMap();
        }
    }

    private Map<Long, ProductVO> getProductsInfo(List<Long> productIds) {
        if (productIds.isEmpty()) {
            return Collections.emptyMap();
        }
        try {
            return productApi.getProductsByIds(productIds).stream().collect(Collectors.toMap(ProductVO::getId, Function.identity()));
        } catch (RpcException e) {
            log.warn("批量获取商品信息失败: {}", e.getMessage());
            return Collections.emptyMap();
        }
    }

    private Map<Long, ReviewReply> getRepliesForReviews(List<Long> reviewIds) {
        if (reviewIds.isEmpty()) {
            return Collections.emptyMap();
        }
        return reviewReplyMapper.selectList(new LambdaQueryWrapper<ReviewReply>().in(ReviewReply::getReviewId, reviewIds))
                .stream().collect(Collectors.toMap(ReviewReply::getReviewId, Function.identity()));
    }

    private Map<Long, List<ReviewImage>> getImagesForReviewItems(List<Long> reviewItemIds) {
        if (reviewItemIds.isEmpty()) {
            return Collections.emptyMap();
        }
        return reviewImageMapper.selectList(new LambdaQueryWrapper<ReviewImage>().in(ReviewImage::getReviewItemId, reviewItemIds))
                .stream().collect(Collectors.groupingBy(ReviewImage::getReviewItemId));
    }
}
